﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Samples.WindowsAzure.ServiceManagement;

namespace InstanceControllerWorker.ManageCommands
{
	public partial class CSManageCommand
	{
		// Values returned during GetDeploymentCommand operation
		public static string ConfigXML { get; set; }	// Configuration is consumed by the ChangeDeploymentConfigCommand
		private static int _currentInstanceCount = 1;
		public static int CurrentInstanceCount			// set/updated by GetDeploymentCommand
		{
			get { return _currentInstanceCount; }
			set { _currentInstanceCount = value; }
		}

		/// <summary>
		/// Gets or sets a value indicating whether to increment or decrement.
		/// Tells the ChangeDeploymentConfigCommand which way to step.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is increment; otherwise, <c>false</c>.
		/// </value>
		public static bool IsIncrement { get; set; }
		/// <summary>
		/// Gets or sets the change increment value up.
		/// Tells the ChangeDeploymentConfigCommand how many instances are requested.
		/// </summary>
		/// <value>The change increment value up.</value>
		public static int IncrementStepValue { get; set; }
		/// <summary>
		/// Gets or sets the change increment value down.
		/// Tells the ChangeDeploymentConfigCommand how many instances are being dropped.
		/// </summary>
		/// <value>The change increment value down.</value>
		public static int DecrementStepValue { get; set; }
		public static int ManualInstances { get; set; }
		public static bool ManualMode { get; set; }
		/// <summary>
		/// Gets or sets a value indicating whether [command was aborted].
		/// The evaluation may indicate a change but may be overriden by other 
		/// rules that stop the command from ever executing
		/// </summary>
		/// <value><c>true</c> if [command was aborted]; otherwise, <c>false</c>.</value>
		public static bool CommandWasAborted { get; set; }
		public static bool TreatWarningsAsError { get; set; }
		/// <summary>
		/// Gets or sets the count of instances to configure with this command.
		/// </summary>
		/// <value>The command to instances.</value>
		public static int CommandToInstances { get; set; }
	}

	public class GetDeploymentCommand : CSManageCommand
	{
		internal const string NamespaceServiceConfiguration = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration";
		
		protected override void PerformOperation(IServiceManagement channel)
		{
			try
			{
				ConfigXML = null;						// clear any old configurations
				Deployment deployment = null;		
				Trace.WriteLine("Getting Deployment", "Information");

				WorkerRole.LogProcess("GetDeploymentCommand", SubscriptionId + " " + HostedServiceName + " " + DeploymentSlot);
				deployment = channel.GetDeploymentBySlot(SubscriptionId, HostedServiceName, DeploymentSlot);
				ConfigXML = ServiceManagementHelper.DecodeFromBase64String(deployment.Configuration);
				WorkerRole.LogProcess("GetDeploymentCommand", "ConfigXML file length: " + ConfigXML.Length);

				// Traversing to Role Instance
				XElement serviceConfig = XElement.Parse(ConfigXML, LoadOptions.SetBaseUri);
				XNamespace xmlns = NamespaceServiceConfiguration;
				var currentInstanceCount = (from c in serviceConfig.Elements(xmlns + "Role")
											where string.Compare(c.Attribute("name").Value, RoleName, true) == 0
											select c.Element(xmlns + "Instances").Attribute("count").Value).FirstOrDefault();
				CurrentInstanceCount = Int32.Parse(currentInstanceCount);

				WorkerRole.LogProcess("GetDeploymentCommand", "Current instance count: " + CurrentInstanceCount);

			}
			catch (Exception ex)
			{
				WorkerRole.LogProcess(ex.InnerException.GetType().Name, ex.Message);
			}
		}
	}

	public class ChangeDeploymentConfigCommand : CSManageCommand
	{
		internal const string NamespaceServiceConfiguration = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration";

		protected override void PerformOperation(IServiceManagement channel)
		{
			var instanceCount = CommandToInstances;
			WorkerRole.LogProcess("PerformOperation", "Setting new instance count to: " + instanceCount);

			try
			{
				// Updating instance count
				XElement serviceConfig = XElement.Parse(ConfigXML, LoadOptions.SetBaseUri);
				XNamespace xmlns = NamespaceServiceConfiguration;
				foreach (XElement p in serviceConfig.Elements(xmlns + "Role"))
				{
					if (string.Compare((string)p.Attribute("name"), RoleName, true) == 0)
						p.Element(xmlns + "Instances").Attribute("count").SetValue(instanceCount.ToString());
				}

				WorkerRole.LogProcess("ChangeDeploymentConfigCommand", "Creating: ChangeConfigurationInput");
				var encodedString = ServiceManagementHelper.EncodeToBase64String(serviceConfig.ToString());
				var input = new ChangeConfigurationInput { Configuration = encodedString };

				if (TreatWarningsAsError)
				{
					input.TreatWarningsAsError = TreatWarningsAsError;
				}

				Trace.WriteLine("Changing Instance Count", "Information");
				WorkerRole.LogProcess("ChangeDeploymentConfigCommand", "Execute:ChangeConfigurationBySlot " + SubscriptionId + " " + HostedServiceName + " " + DeploymentSlot);
				channel.ChangeConfigurationBySlot(SubscriptionId, HostedServiceName, DeploymentSlot, input);

			}
			catch (Exception ex)
			{
				WorkerRole.LogProcess(ex.InnerException.GetType().Name, ex.Message);
			}
		}
	}


}
